using System;
using System.Collections.Generic;
using System.Text;

namespace Framework.StringSplit.Processors
{
    public enum StringSplitTrimType
    {
        None,

        Trim,

        TrimEnd,

        TrimStart
    }
    public abstract class BaseStringSplitProcessor<TResultType> : IStringSplitProcessor<TResultType>
    {
        public abstract TResultType Process(StringSplitHandler parameters, string text);

        //**************************************************************************************************************
        // Simple String Splitting
        //**************************************************************************************************************

        protected string[] Split(string text, char[] seperator, int count, bool removeEmptyEntries, StringSplitTrimType trimType)
        {
            return Splitter(text, seperator, null, count, removeEmptyEntries, trimType);
        }

        protected string[] Split(string text, string[] seperator, int count, bool removeEmptyEntries, StringSplitTrimType trimType)
        {
            return Splitter(text, null, seperator, count, removeEmptyEntries, trimType);
        }

        private string[] Splitter(string text, char[] seperatorChar, string[] seperatorString, int count, bool removeEmptyEntries, StringSplitTrimType trimType)
        {
            if (Is.EmptyString(text) || count == 0)
            {
                return new string[0];
            }

            var options = removeEmptyEntries
                              ? StringSplitOptions.RemoveEmptyEntries
                              : StringSplitOptions.None;

            var result = seperatorChar != null
                             ? text.Split(seperatorChar, count, options)
                             : text.Split(seperatorString, count, options);

            //var trimType =
            //    trimWhitespace
            //        ? 1
            //        : trimWhitespaceRight
            //              ? 2
            //              : trimWhitespaceLeft
            //                    ? 3
            //                    : -1;

            TrimWhiteSpace(result, trimType);

            return result;
        }

        private void TrimWhiteSpace(IList<string> result, StringSplitTrimType trimType)
        {
            if (trimType == StringSplitTrimType.None)
            {
                return;
            }

            for (var i = 0; i < result.Count; i++)
            {
                switch (trimType)
                {
                    case StringSplitTrimType.Trim:
                        result[i] = result[i].Trim();
                        break;
                    case StringSplitTrimType.TrimEnd:
                        result[i] = result[i].TrimEnd();
                        break;
                    case StringSplitTrimType.TrimStart:
                        result[i] = result[i].TrimStart();
                        break;
                }
            }
        }

        //**************************************************************************************************************
        // String Splitting with ability to escape the delimiter characters
        //**************************************************************************************************************

        protected List<string> SplitEscaped(char esc, string text, char[] seperator, int count, bool removeEmptyEntries, StringSplitTrimType trim)
        {
            return SplitterEscaped(esc, text, seperator, null, count, removeEmptyEntries, trim);
        }

        private List<string> SplitterEscaped(char esc, string text, char[] seperatorChar, string[] seperatorString, int count, bool removeEmptyEntries, StringSplitTrimType trim)
        {
            var result = new List<string>();

            if (Is.EmptyString(text) || count == 0)
            {
                return result;
            }

            if (seperatorChar == null)
            {
                throw new Exception(
                    "String Seperators are not currently supported by Split String with Escaped chacharacters");
                // Need to implement this at some time
            }

            //if (Is.EmptyArray(escAppliesTo))
            //{
            //    throw new Exception(
            //        "Please provide a list of characters that the escape character should be applied too");
            //}

            var seperator = seperatorChar;

            var currentlyEscaped = false;
            var fragment = new StringBuilder();

            //_.L("In the lions den");
            //_.Nv("Text", text);
            //_.Nv("Esc", esc);
            //_.Nv("Seperator", Is.EmptyArray(seperatorChar) ? "null" : seperatorChar[0].ToString());
            //_.Nv("Count", count);
//            _.Nv("Text", text);

            foreach (var c in text)
            {
                if (currentlyEscaped)
                {
                    //if (Is.InList(c, escAppliesTo))
                    //{   // Known escape character so lets add it to the fragment
                    //    fragment.Append(c);
                    //}
                    //else
                    //{   // Unknown escape character so lets leave it in place, it may be an escape for a different like it is just an escape on its own, so lets leave it as it is
                    //    fragment.Append(esc);
                    //}
                    fragment.Append(c);

                    currentlyEscaped = false;
                }
                else
                {
                    if (Is.InList(c, seperator))
                    {
                        AddSplitValue(result, fragment, trim, removeEmptyEntries);

                        if (result.Count == count)
                        {
                            return result;
                        }
                    }
                    else if (c == esc)
                    {
                        currentlyEscaped = true;
                    }
                    else
                    {
                        fragment.Append(c);
                    }
                }
            }

            AddSplitValue(result, fragment, trim, removeEmptyEntries);

            return result;
        }

        private void AddSplitValue(ICollection<string> stringList, StringBuilder fragment, StringSplitTrimType trim, bool isRemoveEmptyEntries)
        {
            var fragmentString = fragment.ToString();

            switch (trim)
            {
                case StringSplitTrimType.None:
                    break;
                case StringSplitTrimType.Trim:
                    fragmentString = fragmentString.Trim();
                    break;
                case StringSplitTrimType.TrimEnd:
                    fragmentString = fragmentString.TrimEnd();
                    break;
                case StringSplitTrimType.TrimStart:
                    fragmentString = fragmentString.TrimStart();
                    break;
            }

            if (isRemoveEmptyEntries && Is.EmptyString(fragmentString))
            {
                return;
            }

            stringList.Add(fragmentString);
            fragment.Remove(0, fragment.Length);
        }

    }
}